home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / mrkrls.exe / MRKRLS.PAS < prev   
Pascal/Delphi Source File  |  1993-02-19  |  14KB  |  403 lines

  1. {
  2.  
  3. like many others, I am sure, I  had the need to port a real-mode
  4. program to protected mode, and all memory management was done via
  5. MARK-RELEASE. As we all know,  this is not supported in protected
  6. mode, and  re-writting a large  program to use  getmem-freemem is
  7. practically impossible.  Therefore, I came up  with this piece of
  8. code to simulate the operation  of mark-release. I have tested it
  9. on my program  , and it seems to  work. However, I had to  make a
  10. lot  of assumptions  as to  how the  new memory management works,
  11. without any real documentation. Therefore, I dont trust this code
  12. much. The purpose of uploading it here is threefold:
  13.  
  14. 1. I would like to get comments on the code and my rationale from
  15. people that really understand protected mode
  16.  
  17. 2. I would  like the code to be tested  with more programs than I
  18. could ever write!
  19.  
  20. 3. I want others with the same problem to benefit from it.
  21.  
  22. Therefore, please feel free to  use this code with your programs,
  23. no royalties asked. BUT  there is one thing I DO ask  , and it is
  24. this: PLEASE  let me know if  the code works for  you or not, and
  25. any  problems  that  you  may   encounter  with  it.  This  is  a
  26. developer's   forum,  and   we   would   all  benefit   from  any
  27. comments-problems  you  would  report.  I  am  certain there is a
  28. million  or programs  out there  just DYING  to port to protected
  29. mode,  that are  facing the  same problem.  BE SOCIAL. Share your
  30. opinions with others.
  31.  
  32. The preferred method of contact is E-MAIL, or messages posted in
  33. BPASCAL, section 6, protected mode.
  34.  
  35. Mike Cariotoglou,
  36.  
  37. CIS ID : 100012,1767
  38.  
  39.  
  40. DOCUMENTATION (sort of..)
  41. -------------------------
  42.  
  43. The protected mode memory manager works somewhat like this :
  44.  
  45. The system maintains two variables, HEAPLIMIT and HEAPBLOCK
  46. Any request  for memory >=HEAPLIMIT gets  a "normal" allocation ,
  47. ie  a selector-offset  pointer that  is managed  by the  RTM. Any
  48. request smaller than this, is handled as follows:
  49. The  BP  heap  manager  allocates  a  "Large"  memory block, size
  50. HEAPBLOCK,  and then  "carves" or  sub-allocates this  to smaller
  51. chunks  that  it  passes  to  the  application.  Each large block
  52. maintains its  own freelist of deallocated  pointers, and manages
  53. free "small" blocks very much like T6 memory manager.
  54. (By  large  blocks  I  mean  blocks  >=HEAPLIMIT,  that  are  not
  55. sub-allocated. By  the way, a  program can distinguish  between a
  56. large  and  small  block  by  the  fact  that  the  offset of the
  57. corresponding  pointer is  0 for  a large  block, and  >=12 for a
  58. small block).
  59.  
  60. It follows  from this, that  each large block  behaves like a  T6
  61. heap, along with the 8-byte granularity used by the T6 manager to
  62. reserve space for the free  list entries. However, I believe that
  63. here  the granularity  is 4  bytes, not  8, since  only WORDS are
  64. needed to manipulate a heap of  <=64k. This is not important, and
  65. would  affect only  programs that  assumed and  used this  8-byte
  66. granularity.  I am  sure, however,  that such  programs would  be
  67. bound to do pointer arithmetic  also, meaning they would break in
  68. many more places than this.
  69.  
  70. Each large block has an overhead of 12 bytes, which are used to
  71. maintain the block and link to other large blocks.
  72.  
  73. The manual says that the default for heaplimit and heapblock are
  74. 1024  and   8192,  and  suggests  that   heapblock  is  at  least
  75. 4xHeaplimit.  I  dont  really  see  any  reason  for  that,  so I
  76. experimented with the following values :
  77.  
  78. HEAPBLOCK=65532 ( I believe this has to be a multiple of 4)
  79. HEAPLIMIT=heapblock-12; (the overhead)
  80.  
  81. This gives you  a large block that is similar  to a 64k T6 heap,
  82. and its  performance speedwise is  very acceptable, so  these are
  83. the values I used. It is  important that heaplimit is as large as
  84. possible, since any programs using  the technique I will describe
  85. CANNOT allocate a  block of more than HEAPLIMIT  bytes. The above
  86. values give  a maximum block  of 65520, which  happens to be  the
  87. limit in the old T6 heap manager as well.
  88.  
  89. Each "small heap" of 64k belongs to a circular linked list. The
  90. system variable HEAPLIST holds a selector  that can be used as an
  91. entry point to the circular list. This selector does NOT point to
  92. the  head of  the list   (the first  large block  allocated), but
  93. rather at the most recently used  "small" heap. I believe this is
  94. done  to improve  performance, since  the heap  manager traverses
  95. this list when  asked for memory, and this  ensures that the most
  96. recently used block will be used.
  97.  
  98. Now, the basic idea behind my MARK-RELEASE implemenation:
  99.  
  100. Each time MARK is called,  the current HEAPLIST variable is saved
  101. in a stack, and  then it set to 0. This has  the effect of taking
  102. any  memory  allocated  before  the  MARK  "off-line",  making it
  103. unaccesible to  the heap manager. The  first allocation after the
  104. MARK will create a new 64k  "small" heap, that will be managed by
  105. the heap manager normally. When this  is exausted, a new one will
  106. be allocated, and so on. When RELEASE is called it will :
  107.  
  108. a. de-allocate all 64k heaps that belong to the current HEAPLIST
  109. b. de-allocate all heaplists created up to but not including the
  110.    corresponding MARK
  111. c. restore the heaplist saved when MARK was called.
  112.  
  113. This has the  effect of restoring the memory  state exactly as it
  114. was when the MARK was called.  Note that step (b) above allows us
  115. to  use MARK-RELEASE  in nested  form, and  RELEASE to  any point
  116. MARKED. This often happens in real programs. An example:
  117.  
  118. mark(p1);
  119. ...
  120. ...
  121. ...
  122. mark(p2);
  123. ...
  124. ...
  125. release(p1);
  126.  
  127. This would work with the old  heap manager, and it will also work
  128. here, being the equivalent of :
  129.  
  130. mark(p1);
  131. ...
  132. ...
  133. ...
  134. mark(p2);
  135. ...
  136. ...
  137. release(p2);
  138. release(p1);
  139.  
  140. (actually,  this  system  works  BETTER  than  the old, since any
  141. memory in  the freelist before the  MARK is not lost,  as was the
  142. case  with the  old manager,  which always  cleared the free list
  143. upon a RELEASE)
  144.  
  145. This is the  basic idea, the comments in  the code should clarify
  146. more.
  147.  
  148. Limitations and DONT'S
  149. ----------------------
  150.  
  151. 1.  All   allocations  requested  by  the   application  MUST  be
  152. less than HEAPLIMIT, so that they get sub-allocated. If any block
  153. >= heaplimit is allocated, this memory will NOT belong to a small
  154. heap, therefore will NOT be de-allocated by the release, and will
  155. be  PERMANENTLY lost.  My GETMEM  dummy ensures  this ,by halting
  156. the program in such a case. However, I cannot trap calls to NEW
  157. like that, and therefore the potential for loss of memory exists.
  158. I do not expect many programs to be bothered by it, since the
  159. old real mode heap manager would  NOT allow an allocation of more
  160. than 65520 anyway, so existing  programs should NEVER create this
  161. situation. Still,I thought best to mention it.
  162.  
  163. 2.  Do not  expect multiple  allocations to  give you consecutive
  164. memory space. This was also the case with T6, therefore, again, a
  165. program should not rely on  this. (it would involve pointer math,
  166. anyway, which is a DONT in protected mode)
  167.  
  168. 3. It is best that nested MARK-RELEASE calls are matched. Failing
  169. this, it  is acceptable (as shown  above) to do a  RELEASE with a
  170. pointer  that  was  MARKED  before  the  last  mark (any level of
  171. nesting).  What should  NOT be  done, is  to leave dangling MARKS
  172. around, that are not cleared by a RELEASE with this or a previous
  173. MARK. This would lead the program to die soon, since the internal
  174. stack of UHEAP would overflow. In other words:
  175.  
  176. mark(p1)
  177. ...
  178. release(p1)
  179.  
  180. is best
  181.  
  182. OR
  183.  
  184. mark(p1)
  185. ...
  186. mark(p2)
  187. ...
  188. mark(p3)
  189. ...
  190. release(p1)
  191.  
  192. is OK
  193.  
  194. BUT
  195.  
  196. mark(p1)
  197. ...
  198. mark(p2)
  199. ...
  200. release(p2);
  201.  
  202. (missing RELEASE(p1))
  203.  
  204. is NOT allowed.
  205.  
  206. Unfortunately, this  was allowed in  the old heap  manager, since
  207. MARK did not do anything significant, (what it actually was, was
  208. mark(p) :: p:=heapptr;
  209. Therefore, a situation like this MAY exist in old programs.
  210. you will find out by the fact  that the program will crash with a
  211. runtime error if such a thing exists. A good way to test for this
  212. would be  to take the  program th